<?php
/**
 * <https://y.st./>
 * Copyright © 2017 Alex Yst <mailto:copyright@y.st>
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <https://www.gnu.org./licenses/>.
**/

$xhtml = array(
	'<{title}>' => 'Triangles',
	'<{subtitle}>' => 'Written in <span title="Software Engineering 1">CS 2401</span>, finalised on 2017-12-20',
	'<{copyright year}>' => '2017',
	'takedown' => '2017-11-01',
	'<{body}>' => <<<END
<p>
	The premise of this exercise is that we have a program that takes three numeric values, interprets them as lengths of the sides of a triangle, and outputs whether the triangle is equilateral, isosceles, or scalene.
	We are to propose test inputs to try to find bugs in this program.
	We&apos;re to use at least six test cases, but there is no upper limit to how many tests we can perform, so let&apos;s be thorough.
	We&apos;ll use more tests than that just to be sure.
	With such a simple program, we should be able to automate the tests, so more is better.
	We&apos;ll group the tests into six cases though for ease.
</p>
<p>
	First, let&apos;s define the meaning of the categories.
	An equilateral triangle has three sides of identical lengths.
	These triangles are also known as equiangular triangles, as their angles are identical, or regular triangles, because regular polygons have equal side lengths and angle measurements.
	This is a corner care, and only really requires one test to check, if we&apos;re able to make a certain assumption.
	I&apos;ll cover that assumption in a bit.
	An isosceles triangle has two side lengths that are equal in length.
	One side, any side, is either longer or shorter than the other two.
	A scalene triangle is a triangle that doesn&apos;t fit either of the two other categories, but still has a valid set of side lengths.
	In short, none of the side lengths match; all three sides have different lengths.
</p>
<p>
	Next, let&apos;s think about some possible bizarre values we might get.
	Three particular types of cases stand out as strange things we should additionally test for.
	First, one side of a triangle can&apos;t be longer than the other two sides combined.
	Otherwise, either two of the sides wouldn&apos;t touch (so the shape isn&apos;t enclosed) or the longest side would have to be curved.
	Either way, what we have isn&apos;t a triangle at all.
	The program should recognise this fact, and not categorise such shapes into one of the three categories.
	Another bizarre corner case is that of degenerate triangles.
	Degenerate triangles have zero area.
	Either one side has zero length or two of the sides combined have the same length as the remaining side.
	Yeah.
	Technically speaking, those are very much triangles (Mathwords, 2017) (Rick, 2003) (Wikipedia, 2017), and the program should account for them.
	In the case of two side lengths having a total length equal to the remaining side though, as opposed to the case of one side length equalling zero, these triangles mark the border between what is and is not a valid triangle.
	Third, while values of zero are valid, negative values are not.
	When programming something graphical, a negative length might send something in the opposite direction; for example, negative three pixels to the right would be three pixels to the left.
	However, we don&apos;t measure triangles sides that way in most contexts.
	If the user supplies a negative value for any side length, the triangle should be considered invalid and an error emitted.
</p>
<p>
	Finally, let&apos;s look at some assumptions we should make.
	First, let&apos;s assume our program only accepts numeric data.
	Arbitrary strings are not allowed.
	Furthermore, the assignment specifically specifies that the program takes three <strong>*integers*</strong>.
	That means that floating-point numbers are not allowed either.
	Second, let&apos;s assume the program does not use any hard-coded numbers, anywhere, for any reason.
	Hard-coded numbers would introduce potential bugs in this program for no good reason whatsoever.
	In fact, before we do any testing, we should actually look at the source code, open it up in a good text editor, and use the &quot;find&quot; feature to locate any digits.
	If there are digits, and they&apos;re being used as numeric data (as opposed to parts of variable names or in comments), halt the testing before it begins.
	Fix the problem and remove all hard-coded numeric values.
</p>
<p>
	Now, as this program we&apos;re testing is purely hypothetical, it has no actual $a[API].
	An $a[API] could have been given for the assignment, but it wasn&apos;t.
	To save on verbosity in my test specifications, I&apos;ll define a simple $a[API] to use for testing.
	I&apos;ll assume the program to be tested is a library that provides a single function with this signature: <code>triangle_type(int \$sideA, int \$sideB, int \$sideC): string</code>.
	(It takes three integers and returns a string.)
	The assignment specifies that the program prints out a message telling the triangle type, but for the sake of ease in automation, we&apos;ll assume that the program <strong>*additionally*</strong> returns a string value of <code>&apos;equilateral&apos;</code>, <code>&apos;isosceles&apos;</code>, <code>&apos;scalene&apos;</code>, or <code>&apos;invalid&apos;</code>.
	Without an $a[API] provided, there&apos;s no reason why the program can&apos;t both print out the message and provide a return value for automation and/or embedding in larger programs.
	For these tests, let&apos;s assume that the <code>assert()</code> language construct is configured to throw an exception if the assertion proves <code>false</code>.
	As the exception won&apos;t be caught, it&apos;ll halt the test script and print a debug backtrace, alerting us to an error.
	If the triangle-testing code works properly, no exceptions will be thrown and the test code will exit without error.
</p>
<h2>Invalid triangles</h2>
<p>
	If any one side is longer than the other two sides combined, the side lengths don&apos;t correspond with that of a valid triangle.
	In such a case, the triangle lengths should be rejected.
	We should check to see that the program can detect an impossibly-long side for the case of each of the three sides.
</p>
<blockquote>
<pre><code>assert(triangle_type(20, 8, 2) == &apos;invalid&apos;);
assert(triangle_type(5, 11, 5) == &apos;invalid&apos;);
assert(triangle_type(2, 3, 7) == &apos;invalid&apos;);
echo &quot;Invalid triangles are detected correctly!\\n&quot;;</code></pre>
</blockquote>
<h2>Negative values</h2>
<p>
	Negative side lengths are not permitted.
	To be safe, let&apos;s test making each side negative individually, as well as all combinations of negative sides.
</p>
<blockquote>
<pre><code>assert(triangle_type(3, 5, -7) == &apos;invalid&apos;);
assert(triangle_type(3, -5, 3) == &apos;invalid&apos;);
assert(triangle_type(3, -5, -7) == &apos;invalid&apos;);
assert(triangle_type(-3, 5, 7) == &apos;invalid&apos;);
assert(triangle_type(-7, 5, -7) == &apos;invalid&apos;);
assert(triangle_type(-3, -3, 7) == &apos;invalid&apos;);
assert(triangle_type(-3, -3, -3) == &apos;invalid&apos;);
echo &quot;Negative side lengths are detected correctly!\\n&quot;;</code></pre>
</blockquote>
<h2>Equilateral triangles</h2>
<p>
	Any triangle with three equal-length sides is equilateral.
	As we&apos;ve already checked the code to verify that there are no hard-coded numbers and special values, it should only take one test to verify this particular condition.
	Let&apos;s throw in a couple more tests anyway, just because we can.
</p>
<blockquote>
<pre><code>assert(triangle_type(2, 2, 2) == &apos;equilateral&apos;);
assert(triangle_type(3, 3, 3) == &apos;equilateral&apos;);
assert(triangle_type(5, 5, 5) == &apos;equilateral&apos;);
echo &quot;Equilateral triangles are detected correctly!\\n&quot;;</code></pre>
</blockquote>
<h2>Isosceles triangles</h2>
<p>
	Isosceles triangles have two equal sides.
	The remaining side has some other length.
	Let&apos;s be sure to test both longer and shorter sides for all three sides, for a total of six tests.
</p>
<blockquote>
<pre><code>assert(triangle_type(7, 5, 5) == &apos;isosceles&apos;);
assert(triangle_type(3, 5, 5) == &apos;isosceles&apos;);
assert(triangle_type(11, 5, 11) == &apos;isosceles&apos;);
assert(triangle_type(11, 13, 11) == &apos;isosceles&apos;);
assert(triangle_type(3, 3, 2) == &apos;isosceles&apos;);
assert(triangle_type(3, 3, 5) == &apos;isosceles&apos;);
echo &quot;Isosceles triangles are detected correctly!\\n&quot;;</code></pre>
</blockquote>
<h2>Scalene triangles</h2>
<p>
	Scalene triangles have three sides of differing lengths.
	If the triangle has valid side lengths and it doesn&apos;t fit into one of the two other categories, it fits into this one.
	It&apos;s pretty much a catch-all category for the remaining triangles.
	I thought it&apos;d take more tests to get this right, but there are only six combinations of side length relations to check for.
</p>
<blockquote>
<pre><code>assert(triangle_type(3, 5, 7) == &apos;scalene&apos;);
assert(triangle_type(3, 7, 5) == &apos;scalene&apos;);
assert(triangle_type(5, 3, 7) == &apos;scalene&apos;);
assert(triangle_type(5, 7, 3) == &apos;scalene&apos;);
assert(triangle_type(7, 3, 5) == &apos;scalene&apos;);
assert(triangle_type(7, 5, 3) == &apos;scalene&apos;);
echo &quot;Scalene triangles are detected correctly!\\n&quot;;</code></pre>
</blockquote>
<h2>Degenerate triangles</h2>
<p>
	Degenerate triangles have an area of zero, but as discussed above, they&apos;re still technically triangles.
	In fact, degenerate triangles aren&apos;t even a separate category.
	They can be equilateral (if all the side lengths are zero), isosceles (if one side&apos;s length is zero and the other two side lengths are equal; or if two sides have equal length and the remaining side is double that of one of the other sides), or scalene (if one side&apos;s length is equal to the combined lengths of the remaining sides and all three sides differ in length).
</p>
<blockquote>
<pre><code>assert(triangle_type(0, 0, 0) == &apos;equilateral&apos;);
assert(triangle_type(0, 2, 2) == &apos;isosceles&apos;);
assert(triangle_type(3, 0, 3) == &apos;isosceles&apos;);
assert(triangle_type(5, 5, 0) == &apos;isosceles&apos;);
assert(triangle_type(4, 2, 2) == &apos;isosceles&apos;);
assert(triangle_type(3, 6, 3) == &apos;isosceles&apos;);
assert(triangle_type(5, 5, 10) == &apos;isosceles&apos;);
assert(triangle_type(2, 3, 5) == &apos;scalene&apos;);
assert(triangle_type(2, 5, 3) == &apos;scalene&apos;);
assert(triangle_type(3, 2, 5) == &apos;scalene&apos;);
assert(triangle_type(3, 5, 2) == &apos;scalene&apos;);
assert(triangle_type(5, 2, 3) == &apos;scalene&apos;);
assert(triangle_type(5, 3, 2) == &apos;scalene&apos;);
echo &quot;Degenerate triangles are treated correctly!\\n&quot;;</code></pre>
</blockquote>
<div class="APA_references">
	<h2>References:</h2>
	<p>
		Mathwords. (2017, July 19). Mathwords: Degenerate. Retrieved from <a href="http://mathwords.com/d/degenerate.htm"><code>http://mathwords.com/d/degenerate.htm</code></a>
	</p>
	<p>
		Rick, D. (2003, February 9). Degenerate Triangle. Retrieved from <a href="http://mathforum.org/library/drmath/view/64043.html"><code>http://mathforum.org/library/drmath/view/64043.html</code></a>
	</p>
	<p>
		Wikipedia. (2017, August 22). Degeneracy (mathematics). Retrieved from <a href="https://en.wikipedia.org/wiki/Degeneracy_%28mathematics%29"><code>https://en.wikipedia.org/wiki/Degeneracy_%28mathematics%29</code></a>
	</p>
</div>
END
);
